home *** CD-ROM | disk | FTP | other *** search
Text File | 2011-01-29 | 23.2 KB | 1,154 lines |
-
-
- /***** acf4:net.micro.pc / watrose!jmsellens / 5:08 am Apr 7, 1984*/
-
- X - bug killer
-
-
-
- Here is the source for my version of a very simple 'Make' for
-
- the IBM PC. It requires DOS 2.0, and 'Path' and 'Find' (see
-
- adjacent articles). See below if you need a compiled version
-
- on a floppy. See below details, etc. Sorry about the length
-
- but I hope it's of use. - John
-
- -------------------------------------------------------------
-
- /*
-
- This a called 'Make' and is a much simplified version of
-
- the make utility on UNIX (a trademark or something of AT&T)
-
- written using the DeSmet C compiler/assembler and editor
-
- for the IBM Personal Computer. The DeSmet package is
-
- available from C Ware, P.O. Box 710097, San Jose, California,
-
- 95171-0097, (408) 736-6905 for around $100US. I think it's
-
- a good deal.
-
-
-
- 'Make' takes a file of dependencies (a 'makefile') and
-
- decides what commands have to be executed to bring the files
-
- up to date. These commands are either executed directly from
-
- 'Make' or written to the standard output without executing
-
- them.
-
-
-
- 'Makefile' format:
-
- - There must be a 'makefile'; you can't take input from the
-
- standard input.
-
- - The default name of the 'makefile' is 'MAKEFILE.DAT' on the
-
- default disk. Different 'makefiles' can be specified using
-
- the '-f' option on the command line. If the '-f' option is
-
- used, the default 'makefile' is not processed.
-
- - Any blank lines in the 'makefile(s)' are ignored.
-
- - A line in a 'makefile' that starts with a tab character is
-
- a 'howto' line and consists of a command name followed by
-
- arguments. The command name must be a full file name, e.g.
-
- 'cc.exe'. When commands are executed, the PATH environment
-
- variable is used to find the command, in (hopefully) the
-
- same manner as DOS does. If a command name contains a ':'
-
- or a '\', it is assumed to be a complete pathname and the
-
- PATH is not searched. 'Howto' lines apply to the most
-
- recently preceding 'dependency' line. It is an error for
-
- a 'howto' line to precede the first 'dependency' line.
-
- - Any other non-blank line is a 'dependency' line. 'Dependency'
-
- lines consist of a filename followed by a (possibly empty) list
-
- of dependent filenames.
-
-
-
- Operation:
-
- Syntax:
-
- make [filename] [-f makefilename] [-i] [-n]
-
- -i means continue even if an error is encountered while
-
- executing a command.
-
- -n means don't execute the commands, just write the ones that
-
- should be executed to the standard output. This is useful
-
- for creating batch files, for example.
-
- -f specifies that the following argument is the name of a makefile
-
- to be used instead of the default (MAKEFILE.DAT).
-
- All arguments may be repeated and relative position of the
-
- arguments is not important. If multiple definitions of a file
-
- are found, only the first one is significant.
-
-
-
- First, 'Make' reads all of the makefiles. It then proceeds through
-
- all of the filename arguments, 'making' each one in turn. A file
-
- is remade if it is out of date with respect to the files it depends
-
- on or is non-existent. Dependencies are processed in a 'tree' fashion,
-
- so that the lowest-order files are remade first.
-
-
-
- 'Make' cannot execute DOS built-in commands e.g. 'cd' or 'dir'.
-
- 'Make' uses the first 75k or so after the resident portion of DOS.
-
- 64k of that is stack and heap space: all definitions and howto's
-
- are stored in dynamically allocated struct's. Any executed commands
-
- are loaded above 'Make' in memory.
-
-
-
- 'Make' REQUIRES DOS 2.0 (or higher?).
-
-
-
- 'Make' requires 'Find' and 'Path' in order to search the PATH.
-
- These are in (hopefully) adjacent articles.
-
-
-
-
-
- Known portability problems:
-
- - assembler code embedded in the C code
-
- - uses 'exec()' to execute the commands.
-
- - 'Path' requires that code segment register (CS) be set to the
-
- same value as at program invocation so that the
-
- program segment prefix can be located. This would
-
- probably only be a problem if a "large model"
-
- compiler is used.
-
-
-
- The code is a little kludgy in places.
-
-
-
- No guarantees or warranties of any kind: I think it works and
-
- I use it.
-
-
-
- Any suggestions for improvements gratefully accepted.
-
-
-
- I believe that commercial versions exist. I also beleive that they
-
- would be superior to this.
-
-
-
- If you do not have DeSmet C, I am willing to provide source,
-
- object, and linked files for 'Make', 'Find' and 'Path' for a price.
-
- Send me a floppy in a sturdy mailer, and $15 (you can tell I really
-
- don't want to do this, but I will), and I will return your disk to you.
-
- The $15 includes postage back to you.
-
-
-
-
-
- */
-
-
-
-
-
- /*
-
- Written by John M Sellens, April, 1984
-
-
-
- Code is all original except where indicated otherwise.
-
-
-
- Until August, 1984:
-
- jmsellens@watrose.UUCP
-
-
-
- 107 - 180 Brybeck Cres.
-
- Kitchener, Ontario
-
- N2M 5G4
-
-
-
- After August, 1984:
-
- c/o 1135 Lansdowne Ave. SW
-
- Calgary, Alberta
-
- T2S 1A4
-
-
-
- (c) Copyright 1984 John M Sellens
-
- Permission is granted to use, distribute and/or modify this code unless
-
- done for direct commercial profit. If you find these routines useful,
-
- modest contributions (monetary or otherwise) will be gratefully accepted.
-
- Author's name, address and this notice must be included in any copies.
-
-
-
- */
-
-
-
-
-
-
-
- #include <stdio.h>
-
-
-
- #define DEFAULT "MAKEFILE.DAT"
-
- #define INMAX 130 /* maximum input line length */
-
-
-
- struct howrec {
-
- char *howcom,*howargs;
-
- struct howrec *nexthow;
-
- };
-
-
-
- struct deprec {
-
- char *name;
-
- struct defnrec *def;
-
- struct deprec *nextdep;
-
- };
-
-
-
- struct defnrec {
-
- char *name;
-
- int uptodate;
-
- long modified;
-
- struct deprec *dependson;
-
- struct howrec *howto;
-
- struct defnrec *nextdefn;
-
- };
-
-
-
- struct dorec {
-
- char *name;
-
- struct dorec *nextdo;
-
- };
-
-
-
- struct defnrec *defnlist;
-
- struct dorec *dolist;
-
-
-
- int execute;
-
- int stopOnErr;
-
- int madesomething;
-
- int knowhow;
-
-
-
- main(argc,argv)
-
- int argc;
-
- char *argv[];
-
- {
-
- long make();
-
-
-
- init(argc,argv);
-
-
-
- /* now fall down the dolist and do them all */
-
- while (dolist != NULL) {
-
- madesomething = FALSE;
-
- (void)make(dolist->name); /* ignore return value */
-
- if (!madesomething) {
-
- if (knowhow)
-
- fprintf(stderr,"Make: '%s' is up to date\n",dolist->name);
-
- else {
-
- fprintf(stderr,"Make: Don't know how to make '%s'\n",
-
- dolist->name);
-
- if (stopOnErr)
-
- exit(-1);
-
- }
-
- }
-
- dolist = dolist->nextdo;
-
- }
-
-
-
- }
-
-
-
-
-
- init(argc,argv)
-
- int argc;
-
- char *argv[];
-
- {
-
- int i, usedefault;
-
- dolist = NULL;
-
- defnlist = NULL;
-
- usedefault = TRUE;
-
- execute = TRUE;
-
- stopOnErr = TRUE;
-
-
-
- for (i=1; i < argc; i++) {
-
- if (argv[i][0] == '-') { /* option */
-
- switch (argv[i][1]) {
-
- case 'f': case 'F': /* arg following is a makefile */
-
- if (++i < argc) {
-
- readmakefile(argv[i]);
-
- usedefault = FALSE;
-
- } else {
-
- fprintf(stderr,"Make: '-f' requires filename\n");
-
- exit(-1);
-
- }
-
- break;
-
- case 'i': case 'I': /* ignore errors on execution */
-
- stopOnErr = FALSE;
-
- break;
-
- case 'n': case 'N': /* don't execute commands - just print */
-
- execute = FALSE;
-
- break;
-
- default:
-
- fprintf(stderr,"Make: unknown option '%s'\n",argv[i]);
-
- }
-
- } else { /* it must be something to make */
-
- add_do(argv[i]);
-
- }
-
- }
-
- if (usedefault)
-
- readmakefile(DEFAULT);
-
-
-
- }
-
-
-
- long make(s) /* returns the modified date/time */
-
- char *s;
-
- {
-
- struct defnrec *defnp;
-
- struct deprec *depp;
-
- struct howrec *howp;
-
- long latest, getmodified(), max(), currtime();
-
-
-
- /* look for the definition */
-
- defnp = defnlist;
-
- while (defnp != NULL) {
-
- if (strcmp(defnp->name,s) == 0)
-
- break;
-
- defnp = defnp->nextdefn;
-
- }
-
-
-
- if (defnp == NULL) { /* don't know how to make it */
-
- knowhow = FALSE;
-
- latest = getmodified(s);
-
- if (latest==0) { /* doesn't exist but don't know how to make */
-
- fprintf(stderr,"Make: Can't make '%s'\n",s);
-
- exit(-1);
-
- } else /* exists - assume it's up to date since we don't know */
-
- return(latest);
-
- }
-
-
-
- if (defnp->uptodate)
-
- return(defnp->modified);
-
-
-
- /* now make sure everything that it depends on is up to date */
-
- latest = 0;
-
- depp = defnp->dependson;
-
- while (depp != NULL) {
-
- latest = max(make(depp->name),latest);
-
- depp = depp->nextdep;
-
- }
-
-
-
- knowhow = TRUE; /* has dependencies therefore we know how */
-
-
-
- /* if necessary, execute all of the commands to make it */
-
- /* if (out of date) || (depends on nothing) */
-
- if (latest > defnp->modified || defnp->dependson==NULL) {
-
- /* make those suckers */
-
- howp = defnp->howto;
-
- while (howp != NULL) {
-
- printf("%s %s\n",howp->howcom,howp->howargs);
-
- if (execute) {
-
- char filename[100]; /* extra space */
-
- if (find(howp->howcom,filename)) {
-
- if (exec(filename,howp->howargs) != 0) {
-
- fprintf(stderr,"\nMake: error on '%s %s'",
-
- filename,howp->howargs);
-
- if (stopOnErr)
-
- exit(-1);
-
- }
-
- } else {
-
- fprintf(stderr,"\nMake: Can't find '%s'\n",
-
- howp->howcom);
-
- if (stopOnErr)
-
- exit(-1);
-
- }
-
- putchar('\n'); /* in case command leaves us dangling */
-
- }
-
- howp = howp->nexthow;
-
- }
-
- defnp->modified = currtime();
-
- defnp->uptodate = TRUE;
-
- if (defnp->howto != NULL) /* we had instructions */
-
- madesomething = TRUE;
-
- }
-
-
-
- return(defnp->modified);
-
-
-
- }
-
-
-
-
-
- add_do(s)
-
- char *s;
-
- {
-
- struct dorec *ptr1, *ptr2;
-
- char *getmem();
-
-
-
- ptr1 = getmem(sizeof(struct dorec));
-
-
- ptr1->name = s; /* okay since only called with an argv */
-
- ptr1->nextdo = NULL;
-
-
-
- uppercase(ptr1->name);
-
-
-
- /* now go down the dolist */
-
- if (dolist == NULL)
-
- dolist = ptr1;
-
- else {
-
- ptr2 = dolist;
-
- while (ptr2->nextdo != NULL)
-
- ptr2 = ptr2->nextdo;
-
- ptr2->nextdo = ptr1;
-
- }
-
-
-
- }
-
-
-
-
-
- readmakefile(s)
-
- char *s;
-
- {
-
- int fil, doneline, pos, i, j;
-
- char inline[INMAX], info[INMAX];
-
- char *getmem();
-
- struct defnrec *defnp, *defnp2;
-
- struct deprec *depp, *depp2;
-
- struct howrec *howp, *howp2;
-
-
-
- if ( (fil = open(s,0)) < 0) {
-
- fprintf(stderr,"Make: Couldn't open '%s'\n",s);
-
- return;
-
- }
-
-
-
- while (fgets(inline,INMAX,fil) != NULL) {
-
- inline[strlen(inline)-1] = '\0'; /* strip trailing newline */
-
-
-
- if (inline[0] == '\0') /* ignore blank lines */
-
- continue;
-
-
-
- if (inline[0] != '\t') { /* start of a new definition */
-
- uppercase(inline);
-
-
-
- /* get what we're defining into info */
-
- if (sscanf(inline,"%s ",info) != 1) {
-
- fprintf(stderr,"Make: Can't scan: '%s'\n",inline);
-
- continue;
-
- }
-
- /* get a new struct */
-
- defnp = getmem(sizeof(struct defnrec));
-
- /* add it to the end of defnlist */
-
- if (defnlist == NULL)
-
- defnlist = defnp;
-
- else {
-
- defnp2 = defnlist;
-
- while (defnp2->nextdefn != NULL)
-
- defnp2 = defnp2->nextdefn;
-
- defnp2->nextdefn = defnp;
-
- }
-
- /* initialize it */
-
- defnp->name = getmem(strlen(info)+1);
-
- strcpy(defnp->name,info);
-
- defnp->uptodate = FALSE; /* actually unknown */
-
- defnp->modified = getmodified(defnp->name);
-
- defnp->dependson = NULL;
-
- defnp->howto = NULL;
-
- defnp->nextdefn = NULL;
-
-
-
- /* now go through all of its dependecies */
-
- /* first move past the first name */
-
- pos = 0;
-
- while (isspace(inline[pos]))
-
- pos++;
-
- while (!isspace(inline[pos]) && inline[pos]!='\0')
-
- pos++;
-
- /* now loop through those suckers */
-
- doneline = FALSE;
-
- while (!doneline) {
-
- while (isspace(inline[pos]))
-
- pos++;
-
- if (inline[pos] == '\0') {
-
- doneline = TRUE;
-
- continue;
-
- }
-
- for(i = 0; !isspace(inline[pos]) && inline[pos]!='\0'; )
-
- info[i++] = inline[pos++];
-
- info[i] = '\0';
-
- /* get a new struct */
-
- depp = getmem(sizeof(struct deprec));
-
- /* add it to the end of deplist */
-
- if (defnp->dependson == NULL)
-
- defnp->dependson = depp;
-
- else {
-
- depp2 = defnp->dependson;
-
- while (depp2->nextdep != NULL)
-
- depp2 = depp2->nextdep;
-
- depp2->nextdep = depp;
-
- }
-
- depp->name = getmem(strlen(info)+1);
-
- strcpy(depp->name,info);
-
- depp->nextdep = NULL;
-
- }
-
- } else { /* a how to line */
-
- if (defnp == NULL) {
-
- fprintf(stderr,"Make: Howto line without a definition\n");
-
- fprintf(stderr,"Make: '%s'\n",inline);
-
- }
-
- /* now split the line up into command and args */
-
- for (pos=0;isspace(inline[pos]); pos++);
-
- ;
-
- for (i=pos; !isspace(inline[i]) && inline[i]!='\0'; i++)
-
- ;
-
- /* if there is something there, allocate mem and copy */
-
- if (i != pos) {
-
- /* get a new struct */
-
- howp = getmem(sizeof(struct howrec));
-
- /* add it to the end of howlist */
-
- if (defnp->howto == NULL)
-
- defnp->howto = howp;
-
- else {
-
- howp2 = defnp->howto;
-
- while (howp2->nexthow != NULL)
-
- howp2 = howp2->nexthow;
-
- howp2->nexthow = howp;
-
- }
-
- /* copy command filename */
-
- howp->howcom = getmem(i-pos+1);
-
- for(j=0; pos < i; )
-
- howp->howcom[j++] = inline[pos++];
-
- howp->howcom[j] = '\0';
-
- /* now look for any argumentative part */
-
- while (isspace(inline[pos]))
-
- pos++;
-
- howp->howargs = getmem(strlen(inline)-pos + 1);
-
- for(i=0; inline[pos] != '\0'; )
-
- howp->howargs[i++] = inline[pos++];
-
- howp->howargs[i] = '\0';
-
- howp->nexthow = NULL;
-
- }
-
- }
-
- }
-
- }
-
-
-
-
-
- uppercase(s)
-
- char *s;
-
- {
-
- for( ; *s != '\0'; s++)
-
- *s = toupper(*s);
-
- }
-
-
-
-
-
- char *getmem(size)
-
- int size;
-
- {
-
- char *p;
-
- if ((p = malloc(size)) == 0) {
-
- fprintf(stderr,"Make: Ran out of memory...\n");
-
- exit(-1);
-
- }
-
- return(p);
-
- }
-
-
-
-
-
- long getmodified(name)
-
- char *name;
-
- {
-
- int fil;
-
- long d, dateof();
-
- if ((fil=open(name,0)) >= 0) { /* file exists and was opened */
-
- d = dateof(fil);
-
- close(fil);
-
- } else /* doesn't exist so set very low date */
-
- d = 0;
-
- return(d);
-
- }
-
-
-
- long dateof(fil)
-
- /* return a long encoding the date and time of a file */
-
- /* stolen from DeSmet C distribution */
-
- int fil;
-
- {
-
- static long ret_dt;
-
-
-
- #asm
-
- mov bx,[bp+4] ;file handle is here. only argument.
-
- and bx,0ffh ;low byte of file id is MS-DOS handle.
-
- mov al,0 ;code to retrieve date and time.
-
- mov ah,57h ;dos code for get file date and time.
-
- int 21h ;call dos.
-
- mov word dateof_ret_dt_+2,dx;store date in high word of ret_dt.
-
- mov word dateof_ret_dt_,cx ;store time in low word of ret_dt.
-
- ;note: "dateof_" is added to name
-
- ;because ret_dt is static.
-
- #
-
- return ret_dt;
-
- }
-
-
-
- long currtime()
-
- /* return a long encoding the current date and time */
-
- {
-
- static long ret_dt;
-
-
-
- #asm
-
- mov ah,2Ah ;dos code for get date
-
- int 21h ;call dos.
-
- sbb cx,1980
-
- mov ax,cx ;year
-
- shl ax,1
-
- shl ax,1
-
- shl ax,1
-
- shl ax,1
-
- or al,dh ;month
-
- shl ax,1
-
- shl ax,1
-
- shl ax,1
-
- shl ax,1
-
- shl ax,1
-
- or al,dl ;day
-
- mov word currtime_ret_dt_+2,ax;store date in high word of ret_dt.
-
-
-
- mov ah,2Ch ;dos code for get time
-
- int 21h ;call dos
-
- xor ax,ax
-
- mov al,ch ;hours
-
- shl ax,1
-
- shl ax,1
-
- shl ax,1
-
- shl ax,1
-
- shl ax,1
-
- shl ax,1
-
- or al,cl ;minutes
-
- shl ax,1
-
- shl ax,1
-
- shl ax,1
-
- shl ax,1
-
- shl ax,1
-
- shr dx,1
-
- or al,dh ;number of two second increments
-
- mov word currtime_ret_dt_,ax;store time in low word of ret_dt.
-
- ;note: "dateof_" is added to name
-
- ;because ret_dt is static.
-
- #
-
- return ret_dt;
-
- }
-
-
-
- long max(a,b)
-
- long a,b;
-
- {
-
- return(a>b ? a : b);
-
- }
-
- /* ---------- */
-
- %